package com.chujian.system.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chujian.base.ICols;
import com.chujian.core.entity.CoreDict;
import com.chujian.core.vo.CreDictVo;
import com.chujian.framework.auth.AccessorHolder;
import com.chujian.framework.bean.IdNameCompose;
import com.chujian.framework.core.base.BaseServiceImpl;
import com.chujian.framework.exception.MsgException;
import com.chujian.framework.util.TreeUs;
import com.chujian.system.core.mapper.CoreDictMapper;
import com.chujian.system.core.service.CoreDictService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;


/**
 * 字典表 服务实现类
 *
 * @author chujian
 * @since 2021-07-28
 */
@Service
@Slf4j
public class CoreDictServiceImpl extends BaseServiceImpl<CoreDictMapper, CoreDict> implements CoreDictService, ICols {
    @Autowired
    @Lazy
    private CoreDictService coreDictService;

    @Override
    public IPage<CoreDict> pageParent(Integer current, Integer size, CoreDict coreDict) {
        return this.pageAndFull(current, size,
                new LambdaQueryWrapper<CoreDict>()
                        .eq(CoreDict::getParentId, 0)
                        .eq(StringUtils.isNotEmpty(coreDict.getName()), CoreDict::getDictName, coreDict.getName())
                        .orderByDesc(CoreDict::getDictId)
        );
    }

    @Override
    public List<CoreDict> listByPid(Long dictPid) {
        return this.listAndFull(
                new LambdaQueryWrapper<CoreDict>()
                        .eq(CoreDict::getParentId, dictPid)
                        .orderByAsc(CoreDict::getOrderNo)
        );
    }

    @Override
    public List<CoreDict> getTreeItems(Long dictPid) {
        List<CoreDict> list = this.listAndFull(
                new LambdaQueryWrapper<CoreDict>()
                        .eq(CoreDict::getDictRid, dictPid)
                        .ne(CoreDict::getDictId, dictPid) // 去掉顶级
                        .orderByAsc(CollUtil.newArrayList(CoreDict::getParentId, CoreDict::getOrderNo))
        );
        return toTree(list, dictPid);
    }

    @Override
    public List<IdNameCompose> getSampleTreeItems(Long dictPid) {
        List<CoreDict> dicts = this.getTreeItems(dictPid);
        return convertDict2Compose(dicts);
    }

    private List<IdNameCompose> convertDict2Compose(List<CoreDict> items) {
        if (CollUtil.isEmpty(items)) {
            return null;
        }
        return items
                .stream()
                .map(e -> {
                    IdNameCompose item = new IdNameCompose(e.getDictId(), e.getParentId(), e.getName());
                    item.setChildren(convertDict2Compose(e.getChildren()));
                    return item;
                }).collect(Collectors.toList());
    }

    @Override
    public IPage<CoreDict> pageParentTrees(Integer current, Integer size, CoreDict coreDict) {
        IPage<CoreDict> parentPage = this.pageAndFull(current, size,
                new LambdaQueryWrapper<CoreDict>()
                        .eq(CoreDict::getParentId, 0)
                        .like(StringUtils.isNotEmpty(coreDict.getName()), CoreDict::getDictName, coreDict.getName())
                        .orderByDesc(CoreDict::getDictId)
        );
        if (CollUtil.isNotEmpty(parentPage.getRecords())) {
            List<Long> rids = parentPage.getRecords().stream().map(CoreDict::getDictRid).collect(Collectors.toList());
            List<CoreDict> dictItems = this.list(new QueryWrapper<CoreDict>().in("dict_rid", rids));
            List<CoreDict> treeDicts = toTree(dictItems, 0L);
            for (CoreDict root : parentPage.getRecords()) {
                CoreDict treeRoot = CollUtil.findOne(treeDicts, e -> e.getDictRid().equals(root.getDictRid()));
                if (null != treeRoot) {
                    root.setChildren(treeRoot.getChildren());
                }
            }
        }
        return parentPage;
    }

    private List<CoreDict> toTree(List<CoreDict> dicts, Long pid) {
        return TreeUs.toEntityTree(dicts);
    }

    @Override
    @Transactional
    public void creDict(CreDictVo creDictVo) {
        if (null == creDictVo.getDictId()
                || StringUtils.isEmpty(creDictVo.getDictName())
                || StringUtils.isEmpty(creDictVo.getItems())) {
            throw new MsgException("dictId, dictName, items 不可为空");
        }
        boolean has = hasDictId(creDictVo.getDictId());
        if (has) {
            throw new MsgException("字典ID已存在");
        }
        has = hasParentDict(creDictVo.getDictName());
        if (has) {
            throw new MsgException("字典 【" + creDictVo.getDictName() + "】 已存在");
        }
        Long acId = AccessorHolder.getAcId();
        CoreDict parentDict = new CoreDict()
                .setDictRid(creDictVo.getDictId())
                .setDictId(creDictVo.getDictId())
                .setDictName(creDictVo.getDictName())
                .setAcId(acId);
        parentDict.setParentId(0L);
        coreDictService.save(parentDict);
        int fromIdx = creDictVo.isFrom1() ? 1 : 0;
        addDictItems(parentDict, fromIdx, creDictVo.getItems());
    }

    @Override
    public void addDictItems(CreDictVo creDictVo) {
        if (null == creDictVo.getDictPid() || StringUtils.isEmpty(creDictVo.getItems())) {
            throw new MsgException("dictPid, items 不可为空");
        }
        CoreDict parentDict = this.getById(creDictVo.getDictPid());
        CoreDict maxDict = this.getOne(
                new QueryWrapper<CoreDict>()
                        .select("max(dict_kid) as dict_kid")
                        .eq(parent_id, creDictVo.getDictPid())
                        .in(ac_id, 0, AccessorHolder.getAcId())
        );
        int fromIdx = (maxDict != null && maxDict.getDictKid() != null) ? maxDict.getDictKid().intValue() + 1 : 1;
        addDictItems(parentDict, fromIdx, creDictVo.getItems());
    }

    /**
     * 添加字典项
     *
     * @param parentDict 父级字典
     * @param fromIdx    开始索引
     * @param items      items
     */
    private void addDictItems(CoreDict parentDict, int fromIdx, String items) {
        Long acId = AccessorHolder.getAcId();
        String[] itemsArr = items.replace("，", ",").split(",");
        for (String item : itemsArr) {
            CoreDict dict = new CoreDict()
                    .setDictRid(parentDict.getDictRid())
                    .setDictName(item)
                    .setAcId(acId)
                    .setDictKid((long) fromIdx);
            dict.setParentId(parentDict.getDictId())
                    .setOrderNo(fromIdx);
            coreDictService.save(dict);
            fromIdx++;
        }
    }


    /**
     * 检查是否有字典ID
     *
     * @param dictId dictId
     * @return true字典ID已存在
     */
    public boolean hasDictId(Long dictId) {
        int coreCnt = coreDictService.count(new QueryWrapper<CoreDict>().eq("dict_id", dictId));
        return coreCnt > 0;
    }

    /**
     * 检查字典是否存在
     *
     * @param dictName dictName
     * @return true字典已存在
     */
    public boolean hasParentDict(String dictName) {
        int coreCnt = coreDictService.count(new QueryWrapper<CoreDict>().eq("dict_name", dictName).eq(parent_id, 0L));
        return coreCnt > 0;
    }

}
